package load_balance

import (
	"fmt"
	zookeeper "gitee.com/zhoulvvv/my_go_gateway/zook"
)

// 配置主题
type LoadBalanceConf interface {
	Attach(o Observer)        // 绑定一个观察者
	GetConf() []string        // 获取配置
	WatchConf()               // 监听配置变化
	UpdateConf(conf []string) // 更新配置
}

type LoadBalanceZkConf struct {
	observers    []Observer
	path         string            // zk父节点地址
	zkHosts      []string          // zk集群地址
	confIpWeight map[string]string // 服务器配置的权重和IP
	activeList   []string          // 当前可用的IP列表
	format       string
}

// 绑定观察者
func (s *LoadBalanceZkConf) Attach(o Observer) {
	s.observers = append(s.observers, o)
}

// 通知所有的观察者
func (s *LoadBalanceZkConf) NotifyAllObservers() {
	for _, obs := range s.observers {
		obs.Update()
	}
}

// 获取服务器可用的IP列表
func (s *LoadBalanceZkConf) GetConf() []string {
	confList := []string{}
	for _, ip := range s.activeList {
		weight, ok := s.confIpWeight[ip]
		if !ok {
			weight = "50" //默认weight
		}
		confList = append(confList, fmt.Sprintf(s.format, ip)+","+weight)
	}
	return confList
}

// 更新配置时，通知监听者也更新
func (s *LoadBalanceZkConf) WatchConf() {
	zkManager := zookeeper.NewZkManager(s.zkHosts)
	zkManager.GetConnect()
	fmt.Println("watchConf")
	/// 监听节点变化
	chanList, chanErr := zkManager.WatchServerListByPath(s.path)
	go func() {
		defer zkManager.Close()
		for {
			select {
			case changeErr := <-chanErr:
				fmt.Println("changeErr", changeErr)
			case changedList := <-chanList:
				fmt.Println("watch node changed")
				// 把当前监听节点变化后的地址进行更新
				s.UpdateConf(changedList)
			}
		}
	}()
}

// 更新配置时，通知监听者也更新
func (s *LoadBalanceZkConf) UpdateConf(conf []string) {
	s.activeList = conf
	// 通过观察者模式通知服务器节点发生变化
	for _, obs := range s.observers {
		obs.Update()
	}
}

func NewLoadBalanceZkConf(format, path string, zkHosts []string, conf map[string]string) (*LoadBalanceZkConf, error) {
	zkManager := zookeeper.NewZkManager(zkHosts)
	zkManager.GetConnect()
	defer zkManager.Close()
	zlist, err := zkManager.GetServerListByPath(path)
	if err != nil {
		return nil, err
	}
	mConf := &LoadBalanceZkConf{format: format, activeList: zlist, confIpWeight: conf, zkHosts: zkHosts, path: path}
	// 监听zk节点变化
	mConf.WatchConf()
	return mConf, nil
}

// 负载均衡的观察者模式
type Observer interface {
	Update()
}

// 负载均衡实现观察者接口
type LoadBalanceObserver struct {
	ModuleConf *LoadBalanceZkConf
}

func (l *LoadBalanceObserver) Update() {
	fmt.Println("Update get conf:", l.ModuleConf.GetConf())
}

func NewLoadBalanceObserver(conf *LoadBalanceZkConf) *LoadBalanceObserver {
	return &LoadBalanceObserver{
		ModuleConf: conf,
	}
}
